#include "Channel.h"

Channel::Channel(Epoll *ep, int fd)
    :ep_(ep),fd_(fd)
{

}
// 返回关联的文件描述符
int Channel::fd() const
{
    return fd_;
}
// 返回是否已添加到 epoll 树
bool Channel::inpoll() const
{
    return inepoll_;
}
// 返回当前监视的事件集
uint32_t Channel::events() const
{
    return events_;
}
// 返回实际发生的事件集
uint32_t Channel::revents() const
{
    return revents_;
}

// 事件管理
// 设置使用边缘触发 (EPOLLET) 模式
void Channel::useet()
{
    events_ = events_ | EPOLLET;
}
// 启用读事件监视 (EPOLLIN)
void Channel::enablereading()
{
    events_ = events_ | EPOLLIN;
    ep_->updatechannel(this);
}
// 标记已添加到 epoll 树
void Channel::setinepoll()
{
    inepoll_ = true;
}

void Channel::setrevents(uint32_t ev)
{
    revents_ = ev;
}

void Channel::handleevent()
{
    if (revents_ & EPOLLRDHUP)
    {
        printf("client(eventfd=%d)disconnected\n", fd_);
        close(fd_);
    }
    else if (revents_ & (EPOLLIN | EPOLLPRI))
    {
        readcallback_();
    }
    else if (revents_ & EPOLLOUT)
    {
    }
    else
    { // 其他事件都视为错误
        printf("else error\n");
        close(fd_);
    }
}

Channel::~Channel()
{
}

void Channel::newconnection(Socket* servsock)
{
    InetAddress clientaddr;
    /*
    注意：只能new 否则析构函数会关闭fd
    还有，这里new出来的对象没有释放，这个问题以后再解决
    */
    Socket *clientsock = new Socket(servsock->accept(clientaddr));

    if (clientsock->fd() < 0)
    {
        perror("accept() failed");
        return;
    }

    Channel *clientchannel = new Channel(ep_, clientsock->fd());
    clientchannel->setreadcallback(std::bind(&Channel::onmessage,clientchannel));
    clientchannel->enablereading();
    clientchannel->useet();

    printf("New client connected: %s:%d\n", clientaddr.ip().c_str(), clientaddr.port());
}
void Channel::onmessage()
{
    char buffer[1024];

    while (true)
    {                                   // 非阻塞IO循环读取
        bzero(&buffer, sizeof(buffer)); // 清空缓冲区

        ssize_t nread = read(fd_, buffer, sizeof(buffer));

        if (nread > 0)
        { // 成功读取数据
            printf("recv(eventfd=%d):%s\n", fd_, buffer);

            for (size_t i = 0; i < nread; i++)
            {
                buffer[i] = toupper(buffer[i]);
            }

            send(fd_, buffer, nread, 0); // 原样回发（使用nread而非strlen）
        }
        else if (nread == -1 && errno == EINTR)
        { // 被信号中断
            continue;
        }
        else if (nread == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
        { // 非阻塞无数据
            break;
        }
        else if (nread == 0)
        { // 客户端断开连接
            printf("client(eventfd=%d) disconnected.\n", fd_);
            close(fd_);
            break;
        }
    }
}

void Channel::setreadcallback(std::function<void()> f)
{
    readcallback_ = f;
}